#pragma once

#include <cassert>
#include <cinttypes>
#include <utility>

template<typename DataType>
class TForwardForwardLinkedListNode
{
public:
	DataType* Data=nullptr;
	TForwardForwardLinkedListNode<DataType>* Next=nullptr;	


	TForwardForwardLinkedListNode(const DataType& InData)
		:Data(new DataType(InData))
		//, Next(InNext)
	{
	}

	TForwardForwardLinkedListNode(const DataType&& InData)
		:Data(new DataType(InData))
		//, Next(InNext)
	{
	}

	TForwardForwardLinkedListNode(DataType* InData)
		:Data(InData)
	{
	}

	TForwardForwardLinkedListNode(const TForwardForwardLinkedListNode& OtherNode)
		:Data(OtherNode.Data!=nullptr ?  new DataType(*OtherNode.Data) : nullptr)
		, Next(OtherNode.Next==nullptr? nullptr : new  TForwardForwardLinkedListNode(*OtherNode.Next))
	{
	}

	TForwardForwardLinkedListNode(TForwardForwardLinkedListNode&& OtherNode)
		:Data(OtherNode.Data)
		, Next(OtherNode.Next)
	{
		OtherNode.Data = nullptr;
		OtherNode.Next = nullptr;
	}


	TForwardForwardLinkedListNode()
	{
	}


	~TForwardForwardLinkedListNode()
	{
		delete Data;
		Data = nullptr;
	}

	DataType* operator ->()
	{
		return Data;
	}

	const DataType* operator ->() const 
	{
		return Data;
	}

	DataType& operator*()
	{
		return *Data;
	}

	const DataType& operator*() const
	{
		return *Data;
	}
};

//linked list iterator can be stored before the lowlevel Node destroyed
template<typename DataType>
class TForwardForwardLinkedListIterator
{
	using TNode = TForwardForwardLinkedListNode<DataType>;
public:

	TForwardForwardLinkedListIterator(TNode* InNode)
		:Node(InNode)
	{}

	//std  iterator interface 
	bool operator !=(const TForwardForwardLinkedListIterator& Other) const
	{
		return Node != Other.Node;
	}

	//std  iterator interface 
	TForwardForwardLinkedListIterator& operator ++()
	{
		Node = Node->Next;
		return  *this;
	}

	//std  iterator interface 
	const TForwardForwardLinkedListIterator& operator ++() const
	{
		Node = Node->Next;
		return  *this;
	}

	DataType* operator ->() const
	{
		return Node->Data;
	}

	DataType& operator*() const
	{
		return (*Node->Data);
	}

	DataType* Get() const
	{
		return Node->Data;
	}

	TNode* GetNode() const
	{
		return Node;
	}

private:
	TNode* Node=nullptr;
};

//单向链表
template<typename DataType>
class TForwardForwardLinkedList
{
public:
	using TNode = TForwardForwardLinkedListNode<DataType>;

	TForwardForwardLinkedList()
		: Size(0)
		, Head(nullptr)
	{
	}

	TForwardForwardLinkedList(const TForwardForwardLinkedList& Other)
	{
		Head = Other.Head!=nullptr? new TNode(*Other.Head) : nullptr;
		Size = Other.Size;
	}

	TForwardForwardLinkedList& operator= (const TForwardForwardLinkedList& Other)
	{
		Clear();

		if (Other.Head != nullptr)
		{
			Head = new TNode(*Other.Head);
			Size = Other.Size;
		}
		return *this;
	}

	TForwardForwardLinkedList(TForwardForwardLinkedList&& Other)
	{
		Head = Other.Head;
		Size = Other.Size;

		Other.Head = nullptr;
		Other.Size = 0;
	}
		
	~TForwardForwardLinkedList()
	{
		Clear();
	}

	bool Empty() const
	{
		return Head == nullptr;
	}

	uint64_t Num() const
	{
		return Size;
	}

	void InsertAtHead(const DataType& InData)
	{
		return InsertAtHead((DataType&&)InData);
	}

	void InsertAtHead(DataType&& InData)
	{
		TNode* NewNode = new TNode(std::forward<DataType>(InData));
		InsertAtHead(NewNode);
	}

	void InsertAtHead(TNode* NewNode)
	{
		NewNode->Next = Head;
		Head = NewNode;

		Size++;
	}

	// create a new node and insert at Head
	template<typename... ArgsType>
	void EmplaceAtHead(ArgsType&&... Args)
	{
		TNode* NewNode = new TNode(new DataType(std::forward<ArgsType>(Args)...));
		InsertAtHead(NewNode);
	}
	

	//@Before ,the node before the new one.
	void InsertAfter(TForwardForwardLinkedListIterator<DataType> Before, const DataType& InData)
	{
		assert(Before.Get()!=nullptr && "cant add a new item after end");

		TNode* NewNode = new TNode(InData);
		NewNode->Next = Before->Next;
		Before->Next = NewNode;


		Size++;
	}

	TNode* GetHead() const
	{
		return Head;
	}

	TNode* PopNode()
	{
		assert(Head);

		TNode* OldHead = Head;
		TNode* NewHead = Head->Next;

		OldHead->Next = nullptr;
		Head = NewHead;

		Size--;

		return OldHead;
	}

	void RemoveFirst()
	{
		assert(Head);

		TNode* NewHead = Head->Next;
		//Head->Next = nullptr;
		delete Head;
		Head = NewHead;

		Size--;
	}




	//remove after one
	void RemoveOneAfter(TForwardForwardLinkedListIterator<DataType> Before)
	{
		assert(Before.GetNode()->Next);

		TNode* Next = Before.GetNode()->Next->Next;
		//Before->Next->Next = nullptr;
		delete Before.GetNode()->Next;
		Before.GetNode()->Next = Next;
	
		Size--;
	}
	
	void Clear()
	{
		TNode* Current = Head;
		if (Current)
		{
			TNode* Next = Current->Next;
			delete Current;
			Current = Next;
		}

		Head = nullptr;
		Size = 0;
	
	}

	TForwardForwardLinkedListIterator<DataType> begin()
	{
		return TForwardForwardLinkedListIterator<DataType>(Head);
	}

	const TForwardForwardLinkedListIterator<DataType> begin() const
	{
		return TForwardForwardLinkedListIterator<DataType>(Head);
	}

	TForwardForwardLinkedListIterator<DataType> end()
	{
		return TForwardForwardLinkedListIterator<DataType>(nullptr);
	}

	const TForwardForwardLinkedListIterator<DataType> end() const
	{
		return TForwardForwardLinkedListIterator<DataType>(nullptr);
	}

private:
	uint64_t Size = 0;
	TNode* Head = nullptr;

};